#! /usr/bin/python
#  encoding: utf-8
# ------------------------------------------------------------ 
"""
FileName:       like.py
Author:         TGL<tgl233@qq.com>
CreateDate:     2017/6/6 13:59
Description:    usbcan模块的每个通道相关的类
                Channel     <--->   通道相关的类
                InitConfig  <--->   通道初始化结构体数据类
                DataFrame   <--->   CAN数据结构体相关类
"""
# ------------------------------------------------------------

import ctypes
import sys

_version = '0.0.1'
Version = _version

__all__ = "InitConfig DataFrame  ErrorInformation AcUsb132B".split()

# class WorkMode:
#     """
#     CAN通道工作模式,模拟C语言中的enum数据类型:
#     0   <--->   正常收发模式
#     1   <--->   只听模式
#     """
#     NORMAL = 0  # 正常工作模式
#     LISTEN = 1  # 只听模式
# 
# class BtrType:
#     """
#     CAN通道波特率设置类型：
#     0   <--->   LPC21XX芯片波特率设置类型
#     1   <--->   SJA1000芯片波特率设备类型
#     """
#     LPC21XX = 0  # LPC21XX波特率设置模式
#     SJA1000 = 1  # SJA1000波特率设置模式
# 
# class Btr:
#     """
#     CAN通道的波特率设置：
#     波特率      Btr[0]      Btr[1]      Btr[2]      Btr[3]
#     ------------------------------------------------------
#     5Kbps       0xBF        0xFF        0x00        0x00
#     10Kbps      0x31        0x1C        0x00        0x00
#     20Kbps      0x18        0x1C        0x00        0x00
#     50Kbps      0x09        0x1C        0x00        0x00
#     100Kbps     0x04        0x1C        0x00        0x00
#     125Kbps     0x03        0x1C        0x00        0x00
#     250Kbps     0x01        0x1C        0x00        0x00
#     500Kbps     0x00        0x1C        0x00        0x00
#     800Kbps     0x00        0x16        0x00        0x00
#     1000Kbps    0x00        0x14        0x00        0x00
#     """
#     __5Kpbs = 0xffbf
#     __10Kbps = 0x1C31
#     __20Kbps = 0x1c18
#     __50Kbps = 0x1c09
#     __100Kbps = 0x1c04
#     __125Kbps = 0x1c03
#     __250Kbps = 0x1c01
#     __500Kbps = 0x1c00
#     __800Kbps = 0x1600
#     __1000Kbps = 0x1400
# 
# class FilterMode:
#     """
#     CAN通道滤波模式：
#     0   <--->   不滤波
#     1   <--->   双滤波
#     2   <--->   单滤波
#     """
#     NOFILTER = 0  # 不滤波
#     SINGLE = 1  # 单滤波
#     DOUBLE = 2  # 双滤波

# _baudrate = {'5kbps': 0xffbf, '10kbps': 0x1c31, '20kbps': 0x1c18, '50kbps': 0x1c09, '100kbps': 0x1c04,
#              '125kbps': 0x1c03, '250kbps': 0x1c01, '500kbps': 0x1c00, '800kbps': 0x1600, '1000kbps': 0x1400}
_baudrate = {'5kbps': (ctypes.c_byte * 4)(0xbf, 0xff), '10kbps': (ctypes.c_byte * 4)(0x31, 0x1c),
             '20kbps': (ctypes.c_byte * 4)(0x18, 0x1c), '50kbps': (ctypes.c_byte * 4)(0x09, 0x1c),
             '100kbps': (ctypes.c_byte * 4)(0x04, 0x1c), '125kbps': (ctypes.c_byte * 4)(0x03, 0x1c),
             '250kbps': (ctypes.c_byte * 4)(0x01, 0x1c), '500kbps': (ctypes.c_byte * 4)(0x00, 0x1c),
             '800kbps': (ctypes.c_byte * 4)(0x00, 0x16), '1000kbps': (ctypes.c_byte * 4)(0x00, 0x14)}
_baudrate_mode_dict = {'LPC21XX': 0, 'SJA1000': 1}
_filter_mode_dict = {'not filter': 0, 'double filter': 1, 'single filter': 2}
_work_mode_dict = {'receive and send': 0, 'receive only': 1}


class InitConfig(ctypes.Structure):
    """
    CAN初始化配置类：
    在CAN通道开始收发前,根据初始化配置设备CAN通道
    1、设置通道工作模式
    1、设置通道波特率
    2、设置验收滤波器

    CAN通道的波特率设置：
    波特率      Btr[0]      Btr[1]      Btr[2]      Btr[3]
    ------------------------------------------------------
    5kbps       0xBF        0xFF        0x00        0x00
    10kbps      0x31        0x1C        0x00        0x00
    20kbps      0x18        0x1C        0x00        0x00
    50kbps      0x09        0x1C        0x00        0x00
    100kbps     0x04        0x1C        0x00        0x00
    125kbps     0x03        0x1C        0x00        0x00
    250kbps     0x01        0x1C        0x00        0x00
    500kbps     0x00        0x1C        0x00        0x00
    800kbps     0x00        0x16        0x00        0x00
    1000kbps    0x00        0x14        0x00        0x00

    CAN滤波原理：
    所有AccMask为0的位：AccCode和CAN信息帧的对应位必须相同才算验收通过,
    所在AccMask为1的位：AccCode对应的位验收滤波功能被屏蔽。

    单滤波：
        AccCode跟AccMask组成1组验收滤波器,对CAN信息帧的的前4字节内容进行验收滤波,
        标准帧前4字节内容对应：11位帧ID和前两字节数据
        扩展帧的前4字节内容对应：29位帧ID
    双滤波：
        AccCode跟AccMask组成2组验收滤波器,CAN信息只要通过任意一组滤波器即可验收通过
        AccCode的高位对应ACR0,低位对应ACR3
        AccMask的高位对应AMR0,低位对应AMR3
        标准帧：
            滤波器1由ACR0,ACR1,AMR0,AMR1以及ACR3,AMR3的低4位组成,对应11位标识符、RTR位和数据场第1字节共20位
            滤波器2由ACR2,AMR2及ACR3,AMR3的高4位组成,参于滤波的只有11位标识符和RTR位
        扩展帧：
            滤波器1由ACR0,ACR1,AMR0,AMR1组成,参于滤波的为29位标识符中的高16位
            滤波器2由ACR2,ARC3,AMR2,AMR3组成,参于滤波的为29位标识符中的高16位
    """
    _fields_ = [('_Mode', ctypes.c_byte), ('_BtrType', ctypes.c_byte),  # ('_Btr',ctypes.c_byte * 4),\
                ('_Btr', ctypes.c_byte * 4), ('_AccCode', ctypes.c_uint32), ('_AccMask', ctypes.c_uint32),
                ('_Filter', ctypes.c_byte), ('_Reserved', ctypes.c_byte)]

    # def __init__(self, baudrate, btrType=1, accCode=0, accMask=0xFFFFFFFF, filterMode=0, workMode=0, *args, **kwargs):
    #     """
    #     CAN通道初始化配置对象构造函数
    #     :param baudrate: 波特率设备: '5kpbs','10kbps','20kbps','50kbps','100kbps','125kbps','250kbps','500kbps',
    #                       '800kbps','1000kbps'
    #     :param btrType: 波特率设置类型: 0<-->LPC21XX, 1<--->SJA1000
    #     :param accCode: 验收寄存器
    #     :param accMask: 验收屏蔽寄存器
    #     :param filterMode: 验收滤波模式: 0<--->不滤波, 1<--->双滤波, 2<--->单滤波
    #     :param workMode: 工作模式: 0<--->正常模式, 1<--->只听模式
    #     """
    #     super(InitConfig, self).__init__(*args, **kwargs)  # 调用父类的构造函数
    #     # 参数检查
    #     if not baudrate in _baudrate.keys():
    #         baud_str = 'baudrate must in ['
    #         for s in _baudrate.keys():
    #             baud_str = '{0:s}\'{1}\','.format(baud_str, s)
    #         baud_str += '\b]'
    #         raise AssertionError(baud_str)
    #
    #     self._Mode = workMode
    #     self._BtrType = btrType
    #     self._Btr = _baudrate[baudrate]
    #     self._AccCode = accCode
    #     self._AccMask = accMask
    #     self._Filter = filterMode

    def __init__(self, work_mode="receive and send", baud_rate_typ='SJA1000', baud_rate='250kbps',
                 filter_mode='not filter',
                 accept_code=0x00000000, accept_mask=0xffffffff):
        super(InitConfig, self).__init__()
        try:
            self._Mode = _work_mode_dict[work_mode]
        except:
            raise Exception('work mode must in ' + str(_work_mode_dict.keys()))
        try:
            self._BtrType = _baudrate_mode_dict[baud_rate_typ]
        except:
            raise Exception('baud rate type must in ' + str(_baudrate_mode_dict.keys()))
        try:
            self._Btr = _baudrate[baud_rate]
        except:
            raise Exception("baud rate must in " + str(_baudrate.keys()))
        try:
            self._Filter = _filter_mode_dict[filter_mode]
        except:
            raise Exception("filter mode must in " + str(_filter_mode_dict.keys()))
        self._AccCode = accept_code
        self._AccMask = accept_mask
        self._btr_str = baud_rate

    @property
    def work_mode(self):
        ivert_work_mode = dict([(v, k) for (k, v) in _work_mode_dict.iteritems()])
        return ivert_work_mode[self._Mode]

    @work_mode.setter
    def work_mode(self, value):
        if not (value in _work_mode_dict.keys()):
            message = "work_mode must in ["
            for k in _work_mode_dict.keys():
                message += "'{0:s}',".format(k)
            message += '\b]'
            raise AssertionError(message)
        self._Mode = _work_mode_dict[value]

    @property
    def baud_rate_mode(self):
        ivert_btrtype = dict([(v, k) for (k, v) in _baudrate_mode_dict.iteritems()])
        return ivert_btrtype[self._BtrType]

    @baud_rate_mode.setter
    def baud_rate_mode(self, value):
        if not (value in _baudrate_mode_dict.keys()):
            message = "baud_rate_mode must in ["
            for k in _work_mode_dict.keys():
                message += "'{0:s}',".format(k)
            message += '\b]'
            raise AssertionError(message)
        self._BtrType = _baudrate_mode_dict[value]

    @property
    def baud_rate(self):
        # ivert_baudrate = dict([(v, k) for (k, v) in _baudrate.iteritems()])
        # return ivert_baudrate[int(self._Btr)]
        return self._btr_str

    @baud_rate.setter
    def baud_rate(self, value):
        if not (value in _baudrate.keys()):
            message = "baud_rate must in ["
            for k in _baudrate.keys():
                message += "'{0:s}',".format(k)
            message += '\b]'
            raise AssertionError(message)
        self._Btr = _baudrate[value]
        self._btr_str = value

    @property
    def filter_mode(self):
        ivert_filtermode = dict([(v, k) for (k, v) in _filter_mode_dict.iteritems()])
        return ivert_filtermode[int(self._Filter)]

    @filter_mode.setter
    def filter_mode(self, value):
        if not (value in _filter_mode_dict.keys()):
            message = "filter_mode must in ["
            for k in _filter_mode_dict.keys():
                message += "'{0:s}',".format(k)
            message += '\b]'
            raise AssertionError(message)
        self._Filter = _filter_mode_dict[value]

    @property
    def acc_code(self):
        if self._AccCode < sys.maxint:
            return int(self._AccCode)
        else:
            return self._AccCode

    @acc_code.setter
    def acc_code(self, value):
        self._AccCode = value & 0xffffffff

    @property
    def acc_mask(self):
        if self._AccMask < sys.maxint:
            return int(self._AccMask)
        else:
            return self._AccMask

    @acc_mask.setter
    def acc_mask(self, value):
        self._AccMask = value & 0xffffffff

    def __str__(self):
        print_str = '{0:>16s}\t{1:<s}\n'
        inf = ''
        inf += print_str.format('Name', 'Vaule')
        inf += print_str.format('-' * 16, '-' * 16)
        inf += print_str.format('Work mode', self.work_mode)
        inf += print_str.format('Baud rate mode', self.baud_rate_mode)
        inf += print_str.format('Baud rate', self.baud_rate)
        inf += print_str.format('Filter mode', self.filter_mode)
        inf += print_str.format('Accept code', '0x{0:0<8X}'.format(self.acc_code))
        inf += print_str.format('Accept mask', '0x{0:0<8X}'.format(self.acc_mask))
        # inf += '\b'
        return inf[:-1]


        # def __str__(self):
        #     """
        #     格式化输出InitConfig对象,如下：
        #                 Name:	Value
        #     ----------------------------------------
        #            Work mode:	Listen only
        #       Baud rate mode:	SJA1000
        #            Baud rate:	250kbps
        #          Filter mode:	Double filter
        #       Filter AccCode:	0x00000000
        #       Filter AccMask:	0xFFFFFFFF
        #
        #     """
        #     strTemplate = '{0:>16s}:\t{1:<s}'
        #     head = strTemplate.format('Name', 'Value') + '\n' + '-' * 40
        #     if self._Mode == 0:
        #         str_workmode = strTemplate.format('Work mode', 'Nomarl')
        #     else:
        #         str_workmode = strTemplate.format('Work mode', 'Listen only')
        #     if self._BtrType == 0:
        #         str_baudmode = strTemplate.format('Baud rate mode', 'LPC21XX')
        #     else:
        #         str_baudmode = strTemplate.format('Baud rate mode', 'SJA1000')
        #     # 波特率的反向字典
        #     ivert_baudrate = dict((v, k) for (k, v) in _baudrate.iteritems())
        #     str_baudrate = strTemplate.format('Baud rate', ivert_baudrate[self._Btr])
        #     if self._Filter == 0:
        #         str_filtermode = strTemplate.format('Filter mode', 'Not filter')
        #     elif self._Filter == 1:
        #         str_filtermode = strTemplate.format('Filter mode', 'Double filter')
        #     else:
        #         str_filtermode = strTemplate.format('Filter mode', 'Single filter')
        #
        #     str_code = strTemplate.format('Filter AccCode', '0x{0:0<8X}'.format(self._AccCode))
        #     str_mask = strTemplate.format('Filter AccMask', '0x{0:0<8X}'.format(self._AccMask))
        #
        #     return '{0}\n{1}\n{2}\n{3}\n{4}\n{5}\n{6}'.format(head, str_workmode, str_baudmode,
        #                                                       str_baudrate, str_filtermode, str_code, str_mask)


_send_mode_dict = {"send normal": 0, "send once": 1, "look back": 2, "look back once": 3}


class DataFrame(ctypes.Structure):
    """
    Like UsbCan模块对应的CAN数据帧类
    id:             CAN帧的ID
    data:           CAN帧包含的数据内容
    data_len:       CAN帧中包含的数据长度
    remote_flag:    是否是远程帧
    external_flag:    是否是扩展帧
    send_mode :     数据发送模式
        "send normal"       <---> 正常收发
        "send once"         <---> 单次发送
        "look back"         <---> 自发自收
        "look back once"    <---> 单次自发自收
    time_span:      接收CAN帧的时间(从通道开启时开始计时),对发送数据不起作用
    """
    _fields_ = [('_time_flag', ctypes.c_uint32), ('_send_type', ctypes.c_byte), ('_remote_flag', ctypes.c_byte),
                ('_external_flag', ctypes.c_byte), ('_data_len', ctypes.c_byte), ('_id', ctypes.c_uint32),
                ('_data', ctypes.c_ubyte * 8)]

    def __init__(self, send_type='look back', remote_flag=False, external_flag=False, ID=0,
                 data=None):
        """
        DataFrame([send_type='look back',[remote_flag=False,[external_flag=False,[data=[0,0,0,0,0,0,0,0]]]]])
        """
        if data is None:
            data = [0, 0, 0, 0, 0, 0, 0, 0]

        super(DataFrame, self).__init__()

        try:
            self._send_type = _send_mode_dict[send_type]
        except:
            raise Exception("send_type must in " + str(_send_mode_dict.keys()))

        self._remote_flag = int(remote_flag)
        self._external_flag = int(external_flag)
        self._id = long(ID)

        if len(data) <= 8:
            for i, value in enumerate(data):
                self._data[i] = value
            self._data_len = len(data)
        else:
            raise Exception, "Data length can't beyond 8"
            # -------------------------------------------------
            # self._data = (ctypes.c_byte * 8)(1,2,3,4,5,6,7,8)
            # eight_byte_array = ctypes.c_byte * 8
            # self._data = eight_byte_array(8,7,6,5,4,3,2,1)

    # def get_data(self):
    #     """
    #     DataFrame.get_data() -> tuple()
    #     读取CAN数据帧的内容,并以元组的形式返回
    #     :return: CAN帧数据对应的tuple
    #     """
    #     return tuple([int(i) for i in self._data])
    #
    # def set_data(self, *args):
    #     """
    #     DataFrame.set_data(1,2,3,4,5,6,7,8)
    #     设备CAN数据帧的内容
    #     :param args: 长度不超过8的字节无组
    #     :return: None
    #     """
    #     assert len(args) <= 8, "Data length can't beyond 8"
    #     for i, value in enumerate(args):
    #         self._data[i] = value
    #     self._data_len = len(args)

    @property
    def data(self):
        """
        DataFrame.data -> list()
        """
        result = [int(i) for i in self._data]
        return result[:self.data_len]

    @data.setter
    def data(self, value):
        """
        DataFrame.data = (1, 2, 3, 4, 5, 6, 7, 8)
        """
        if len(value) <= 8:
            for i, dat in enumerate(value):
                self._data[i] = dat
            self._data_len = len(value)

    @property
    def id(self):
        if self._id < sys.maxint:  # sys.maxint <---> 0x7FFFFFFF
            return int(self._id)
        else:
            return self._id

    @id.setter
    def id(self, value):
        assert isinstance(value, long), "ID must is long"
        self._id = value

    @property
    def data_len(self):
        return int(self._data_len)

    @property
    def external_flag(self):
        return bool(self._external_flag)

    @external_flag.setter
    def external_flag(self, value):
        self._external_flag = int(value)

    @property
    def remote_flag(self):
        return bool(self._remote_flag)

    @remote_flag.setter
    def remote_flag(self, value):
        self._remote_flag = bool(value)

    @property
    def time_span(self):
        return self._time_flag

    @property
    def send_mode(self):
        """
        CAN数据帧的发送模式
        "send normal"       <---> 正常收发
        "send once"         <---> 单次发送
        "look back"         <---> 自发自收
        "look back once"    <---> 单次自发自收
        """
        ivert_sendtype = dict([(v, k) for (k, v) in _send_mode_dict.iteritems()])
        return ivert_sendtype[self._send_type]

    @send_mode.setter
    def send_mode(self, value):
        # assert not (value in _send_mode_dict.keys()), "send_mode must in " + _send_mode_dict.keys()
        if not (value in _send_mode_dict.keys()):
            message = 'send_mode must in ['
            for k in _send_mode_dict.keys():
                message += "'{0:s},'".format(k)
            message += '\b]'
            raise AssertionError(message)
        self._send_type = _send_mode_dict[value]

    def __str__(self):
        print_str = '{0:>16s}\t{1:<s}\n'
        inf = ''
        inf += print_str.format('Name', 'Vaule')
        inf += print_str.format('-' * 16, '-' * 40)
        inf += print_str.format('Time span', '0x{0:0<8X}'.format(self.time_span))
        inf += print_str.format('Send mode', self.send_mode)
        inf += print_str.format('Remote frame', str(self.remote_flag))
        inf += print_str.format('External frame', str(self.external_flag))
        inf += print_str.format('Data length', '0x{0:02X}'.format(self.data_len))
        inf += print_str.format('Data Id', '0x{0:02X}'.format(self.id))
        data_str = ''
        # for i in self.get_data():
        for i in self.data:
            data_str += "0x{0:02X} ".format(i)
        inf += print_str.format('Data', data_str)
        # inf += '\b'
        return inf[:-2]


class DeviceInformation(ctypes.Structure):
    _fields_ = [("_hardware_version", ctypes.c_ushort), ('_firmware_version', ctypes.c_ushort),
                ('_driver_version', ctypes.c_ushort), ('_interface_version', ctypes.c_ushort),
                ('_interrupt_version', ctypes.c_ushort), ('_channel_number', ctypes.c_ubyte),
                ('_serial_number', ctypes.c_char * 20), ('_hardware_type', ctypes.c_char * 40),
                ('_description', ctypes.c_char * 20)]

    # def __init__(self, *args, **kwargs):
    #     super(DeviceInformation, self).__init__(*args, **kwargs)

    @staticmethod
    def _int_to_version_str(version_number):
        result = ''
        _str = "{0:04X}".format(version_number)
        for s in _str:
            result += s + '.'
        return result + '\b'

    def __str__(self):
        return """\
Hardware version = {0}
Firmware version = {1}
Driver version = {2}
Interface version = {3}
Interrupt number = {4}
Channel number = {5}
Serial number = {6}
Hardware type = {7}
Description = {8}""".format(self._int_to_version_str(self._hardware_version),
                            self._int_to_version_str(self._firmware_version),
                            self._int_to_version_str(self._driver_version),
                            self._int_to_version_str(self._interface_version),
                            self._int_to_version_str(self._interrupt_version),
                            self._channel_number, self._serial_number, self._hardware_type, self._description)

    def __getitem__(self, item):
        if item == "hardware":
            return self._int_to_version_str(self._hardware_version)[:7]
        elif item == "firmware":
            return self._int_to_version_str(self._firmware_version)[:7]
        elif item == "driver":
            return self._int_to_version_str(self._driver_version)[:7]
        elif item == "interface":
            return self._int_to_version_str(self._interface_version)[:7]
        elif item == "interrupt":
            return self._int_to_version_str(self._interrupt_version)[:7]
        elif item == "channel":
            return str(self._channel_number)
        elif item == "SN":
            return str(self._serial_number)
        elif item == "type":
            return str(self._hardware_type)
        elif item == "desc":
            return str(self._description)
        else:
            raise Exception, "{0:s} is not in ['hardware','firmware','driver','interface','interrupt'," \
                             "'channel','SN','type','desc'] "


error_code_dict = {0x0: u"没有发现错误", 0x1: u"CAN控制器内部FIFO溢出", 0x2: u"CAN控制器错误报警",
                   0x4: u"CAN控制器消极错误", 0x8: u"CAN控制器仲裁丢失", 0x10: u"CAN控制器总线错误",
                   0x100: u"设备已打开", 0x200: u"打开设备失败", 0x400: u"设备没有打开", 0x800: u"缓冲区溢出",
                   0x1000: u"些设备不存在", 0x2000: u"装载动态库失败", 0x4000: u"执行命令失败错误码",
                   0x8000: u"内存不足"}


class ErrorInformation(ctypes.Structure):
    _fields_ = [("_error_code", ctypes.c_uint32), ("_passive_error_data", ctypes.c_byte * 4),
                ('_ar_lost_error_data', ctypes.c_byte)]

    @property
    def passive_error_data(self):
        result = []
        for item in self._passive_error_data:
            result.append(item)
        return result

    @property
    def lost_error_data(self):
        return self._ar_lost_error_data

    @property
    def error_code(self):
        return self._error_code

    @staticmethod
    def translation(error_code, encoding='utf-8'):
        try:
            return error_code_dict[error_code].encode(encoding)
        except:
            raise "The 0x{0:x} is an don't know error code".format(error_code)

    def __str__(self):
        result_str = ""
        result_template = "{0:>20s} = {1:s}\n"
        result_str += result_template.format("Error message", self.translation(self.error_code))
        result_str += result_template.format("passive_error_data", str([hex(i) for i in self.passive_error_data]))
        result_str += result_template.format("lost_error_data", hex(self.lost_error_data))
        return result_str[:-1]


# _dll = ctypes.windll.LoadLibrary('./lib/CanCmd.dll')
_dll = ctypes.WinDLL("./lib/CanCmd.dll")

# _Open = _dll.CAN_DeviceOpen
# _Open.argtypes = [ctypes.c_int, ctypes.c_int, ctypes.c_char_p]
# _Open.restype = ctypes.c_int

_device_type_dict = {"ACUSB131B": 1, "ACUSB132B": 2}


class UsbCan(object):
    def __init__(self, device_type='ACUSB132B', index=0):
        self._type = _device_type_dict[device_type]
        self._index = index
        self._handle = 0
        self._is_open = False

    def open(self):
        handle = _dll.CAN_DeviceOpen(self._type, self._index, ctypes.c_char_p("UsbCan Device"))
        self._handle = handle
        if handle:
            self._is_open = True
        return bool(handle)

    def close(self):
        result = _dll.CAN_DeviceClose(self._handle)
        if result:
            self._handle = 0
            self._is_open = False
        return bool(result)

    def get_device_information(self):
        if not self._is_open:
            raise Exception, "The device is not open"
        result = DeviceInformation()
        _dll.CAN_GetDeviceInfo(self._handle, ctypes.byref(result))
        return result

    @property
    def handle(self):
        return self._handle

    @property
    def index(self):
        return self._index

    @property
    def device_type(self):
        invert_device = dict([(v, k) for (k, v) in _device_type_dict.iteritems()])
        return invert_device[self._type]

    @property
    def is_open(self):
        return self._is_open


class Channel(object):
    def __init__(self, handle, channel, config):
        self._handle = handle
        self._channel = channel
        self._config = config
        self._is_run = False

    def start(self):
        """
        Channel.start() --> bool
        通道开始收发
        :return: bool
        """
        if self._handle == 0:
            print(u"开启CAN通道，必须先打开设备！")
            return False

        result = _dll.CAN_ChannelStart(self._handle, self._channel, ctypes.byref(self._config))
        if result:
            self._is_run = True
        return bool(result)

    def stop(self):
        result = _dll.CAN_ChannelStop(self._handle, self._channel)
        if result:
            self._is_run = False
        return bool(result)

    def send(self, data):
        if self.is_run:
            return bool(_dll.CAN_ChannelSend(self._handle, self._channel, ctypes.byref(data), 1))
        else:
            raise Exception("Channel is not run")

    def receive(self, wait_timeout=-1):
        if self.is_run:
            result = DataFrame()
            if _dll.CAN_ChannelReceive(self._handle, self._channel, ctypes.byref(result), long(1), wait_timeout):
                return result
            else:
                return None
        else:
            raise Exception("Channel is not run")

    def get_error_information(self):
        err = ErrorInformation()
        if _dll.CAN_GetErrorInfo(self._handle, self._channel, ctypes.byref(err)):
            return err
        else:
            return None

    @property
    def count(self):
        if self.is_run:
            return _dll.CAN_GetReceiveCount(self._handle, self._channel)
        else:
            raise Exception("Channel is not run")

    @property
    def is_run(self):
        return self._is_run

    @property
    def channel_handle(self):
        return self._handle

    @property
    def channel_number(self):
        return self._channel

    @property
    def channel_config(self):
        return self._config

    @channel_config.setter
    def channel_config(self, value):
        if self._is_run:
            raise Exception('Channel is runing can\'t change the config')
        else:
            assert not isinstance(value, InitConfig), "{0} not instance of InitConfig".format(value)
            self._config = value


class AcUsb132B(UsbCan):
    def __init__(self, index=0):
        super(AcUsb132B, self).__init__("ACUSB132B", index)
        # UsbCan.__init__(self, 'ACUSB132B', index)
        # self._can0 = Channel(self.handle, 0, InitConfig())
        # self._can1 = Channel(self.handle, 1, InitConfig())
        self._can0 = Channel(self.handle, 0, InitConfig())
        self._can1 = Channel(self.handle, 1, InitConfig())

    def open(self):
        """
        AcUsb132B().open() --> bool
        打开设备
        :return: bool
        """
        if super(AcUsb132B, self).open():
            self._can0 = Channel(self.handle, 0, self._can0.channel_config)
            self._can1 = Channel(self.handle, 1, self._can1.channel_config)
            return True
        else:
            print(u"""检查模块的SYS灯是否常绿：
    是：请以管理员身份动行程序
    否：更新驱动程序或模块"""[1:])
            return False

    def close(self):
        """
        AcUsb132B().close() ---> bool
        关闭设备
        :return: bool
        """
        if self._can0.is_run:
            self._can0.stop()
        if self._can1.is_run:
            self._can1.stop()
        if super(AcUsb132B, self).close():
            self._can0 = Channel(self.handle, 0, self._can0.channel_config)
            self._can1 = Channel(self.handle, 1, self._can1.channel_config)
            return True
        else:
            return False

    @property
    def can0(self):
        return self._can0

    @property
    def can1(self):
        return self._can1
